/*********************************************************************************
 *      Copyright:  (C) HuangXiangming
 *                  All rights reserved.
 *
 *       Filename:  client.c
 *    Description:  This file is temperature reporting client
 *               
 *        Version:  1.0.0(25/04/03)
 *         Author:  Huang Xiangming <huangxiangming@gmail.com>
 *      ChangeLog:  1, Release initial version on "25/04/03 13:10:30"
 *                 
 *********************************************************************************/

#include <sys/wait.h>
#include <sys/types.h>		//socket、connect
#include <sys/socket.h>
#include <stdbool.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>		//strerror
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>		//getopt
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <time.h>
#include <signal.h>
#include <sys/types.h>
#include <pthread.h>

#include "get_data.h"
#include "sqlite_client.h"
#include "socket.h"
#include "logger.h"

static int              timeset = 30;       //默认上报时间间隔30s
static int				alarm_flag = 0;	//温度上报开关标志(1发送0停止)

 //信号处理函数
void clock_handler(int signum) 
{
	if ( SIGALRM == signum )
	{  
		alarm_flag = 1;
	}

	alarm(timeset);
}


int main(int argc, char **argv)
{
	struct sockaddr_in      servaddr;
	int						rv = 0;
//	int                     sockfd = -1;
//	char					*host = NULL;
//	int						reconnected = 0;
//	int						port = 0;		//本机字节序
	char					buf[1024];
	int                     ch;
	int						total = -1;
	int						daemon_run = 0;
	int						report_flag = 0;
	int						sn = 1;

	char					*logfile = "client.log";
	char					loglevel = LOG_LEVEL_INFO;
	
	int 					error;
	socklen_t 				len_error = sizeof(error);

	pack_t					data;
	socket_t				sock;

	sock.sockfd = -1;
	//sock.hostname = NULL;
	sock.port = 0;
	sock.connected = 0;

	struct option 			opts[] = {
		{"ipaddr", required_argument, NULL, 'i'},		
		{"port", required_argument, NULL, 'p'},			
		{"help", no_argument, NULL, 'h'},
		{"time", required_argument, NULL, 't'},
		{"background", no_argument, NULL, 'b'},
		{"debug", no_argument, NULL, 'd'},
		{"sn", required_argument, NULL, 's'},
		{NULL, 0, NULL, 0}
		
	};

	//命令行解析
	while ((ch = getopt_long(argc, argv, "i:p:ht:bds:", opts, NULL)) != -1)
	{
		switch (ch)
		{
			case 'i':
					strcpy(sock.hostname, optarg);
					break;

			case 'p':
					sock.port = atoi(optarg);
					break;

			case 'h':
					print_usage(argv[0]);
					return 0;
			case 't':
					timeset = atoi(optarg);
					break;
			case 'b':
					daemon_run = 1;
					break;
			case 'd':
					logfile = "stdout";
					loglevel = LOG_LEVEL_DEBUG;
					break;
			case 's':
					sn = atoi(optarg);
					break;
			default:
					print_usage(argv[0]);
					return 0;
		}
	}

	//端口检查
	if ( !sock.hostname || !sock.port )
	{
		print_usage(argv[0]);
		return 0;
	}

	//安装信号
	signal(SIGALRM, clock_handler);
	signal(SIGPIPE, SIG_IGN);

	//日志初始化
	if ( logger_init(logfile, loglevel) < 0)
	{
		fprintf(stderr, "initial logger system failure\n");
		return 0;	//成功返回0，出错返回非零整数
	}  

	//后台运行
	if ( daemon_run )
	{
		daemon(1, 1);
		log_info("Running daemon successfully!\n");
	}

	//获取序列号
	get_devid(data.id, sizeof(data.id)-1, sn);

	//数据库初始化
	if ( sqlite_init(data.id) < 0)
	{
		return 0;
	}
	
	//时钟设置
	alarm(timeset);

	//socket_connect_cp(&sockfd, port, host, &reconnected);

	while(1)
	{
		report_flag = 0;

		//获取温度、时间、序列号
		if ( alarm_flag == 1 )
		{
			get_data(&data);
			
			report_flag = 1;
			alarm_flag = 0;
		}


		//判断连接状态、服务器连接
		if (getsockopt(sock.sockfd, SOL_SOCKET, SO_ERROR, &error, &len_error) < 0 || error != 0)
		{
			log_warn("connect failed: %s\n", strerror(errno));
			sock.connected = 0;
		}

		if ( sock.connected == 0 )
		{
			close(sock.sockfd);
		
			log_info("Attempting to connect...\n");

			log_info("hostname=%s\n", sock.hostname);
			log_info("port=%d\n", sock.port);
			log_info("sockfd=%d\n", sock.sockfd);
			log_info("connected=%d\n", sock.connected);
			//socket_connect(&sock.sockfd, host, sock.port, &sock.connected);
			socket_connect(&sock);
		}
		
		//socket断开：如果采样时间到，将数据存入数据库	
		if ( sock.connected == 0 ) 
		{   
			if ( report_flag )
			{
				log_info("Insert data into client sqlite...\n");
			    
				sqlite_inset(&data);
			}
			sleep(2);
			continue;
		} 

		if( report_flag == 1 )
		{
			//socket连接：采样时间到，上报数据；2.采样时间没到，同步数据库数据到服务器
			log_info("sent data to server...\n");
			
			pack_data(&data, buf, sizeof(buf));

			rv = read_write(sock.sockfd, buf);
			if ( rv < 0 )
			{
				sock.sockfd = -1;
				sock.connected = 0;
					
				log_info("Insert data into client sqlite...\n");
				sqlite_inset(&data);
			}		
		}

		if( get_database_1st_record(&data) > 0 )
		{
			log_info("sqlite database have data!will sent...\n");

			pack_data(&data, buf, sizeof(buf));

			rv = read_write(sock.sockfd, buf);
			if ( rv < 0 )
			{
				sock.sockfd = -1;
				sock.connected = 0;
				log_warn("synchronization failure\n\n");
				continue;
			}

			delete_record(&data);

			log_info("synchronization secessful!\n");
		}

		sleep(2);
	}
		
	//服务器断开连接
	log_info(" Client process exiting...\n");
	close(sock.sockfd);
	logger_term();
	sqlite_close();

	return 0;
}

